package library

import (
	"fmt"
	"io/ioutil"
	"os"
	"sync"
	"time"
)

const (
	SyncTime = 500 * time.Millisecond
)

type bitmap struct {
	bytes []byte
	len   int64
	rw    sync.RWMutex
	path  string
}

var BitmapCtx *bitmap

func init() {
	BitmapCtx = &bitmap{
		path: "./test.txt",
	}
	file, err := os.OpenFile(BitmapCtx.path, os.O_RDONLY|os.O_CREATE, 0666)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	BitmapCtx.bytes, err = ioutil.ReadAll(file)
	fmt.Println(len(BitmapCtx.bytes))
	if err != nil {
		panic(err)
	}
	go BitmapCtx.async()
}
func (b *bitmap) async() {
	timer := time.NewTimer(SyncTime)
	//及时关闭file句柄
	defer timer.Stop()
	for {
		<-timer.C
		if len(b.bytes) > 0 {
			file, err := os.OpenFile(b.path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
			if err != nil {
				file.Close()
				panic(err)
			}
			n, err := file.Write(b.bytes)
			if err != nil {
				file.Close()
				panic(err)
			}
			file.Close()
			fmt.Printf("同步文件成功，写入字节数：%d\n", n)
		}
		timer.Reset(SyncTime)
	}
}
func (b *bitmap) SetBit(position int64, bitValue byte) {
	b.rw.Lock()
	offset := position & 7 //获取偏移量
	byteIndex := position / 8
	for position > b.len*8-1 {
		b.bytes = append(b.bytes, 0)
		b.len++
	}
	offsetVal := bitValue & 1
	if offsetVal == 0 {
		offsetVal = ^(1 << (7 - offset))
		b.bytes[byteIndex] = (offsetVal & b.bytes[byteIndex])
	} else {
		b.bytes[byteIndex] |= 1 << (7 - offset)
	}
	b.rw.Unlock()
}

func (b *bitmap) IsExist(position int64) (exist bool) {
	b.rw.RLock()
	defer b.rw.RUnlock()
	if position > b.len*8 {
		return
	}
	offset := position & 7 //获取偏移量
	byteIndex := position / 8

	offsetVal := (b.bytes[byteIndex] >> (7 - offset)) & 1
	if offsetVal == 1 {
		exist = true
	}
	return
}
func (b *bitmap) GetString() string {
	return string(b.bytes)
}

func (b *bitmap) GetBytes() []byte {
	return b.bytes
}
func (b *bitmap) Count() int64 {
	var num int64 = 0
	for _, v := range b.bytes {
		for v > 0 {
			v = v & (v - 1)
			num++
		}
	}
	return num
}
